﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace 并行与异步
{
    class Program
    {

        static void Main(string[] args)
        {


            string url = "http://www.cz88.net/ip/index.aspx?ip=113.106.167.178";
          string regStr = "(?<=<span\\s*id=\\\"cz_addr\\\">).*?(?=</span>)";
          //得到网页源码
          string html = ClassLibrary1.http.HttpGet(url,null,"gb2312");
          Regex reg = new Regex(regStr, RegexOptions.None);
          Match ma = reg.Match(html);
          html = ma.Value;
          string[] arr = html.Split(' ');
        
      



            string ipinfo = ClassLibrary1.http.getIPwhere("113.106.167.178");
            if (!string.IsNullOrEmpty(ipinfo))
            {
                string[] ipsplit = ipinfo.Split('\t');
            }


            int i = 0;
            while (true)
            {
                try
                {
                    i++;
                    Console.WriteLine(i);
                    test4();
                    //test3();

                }
                catch (AggregateException ex)//并行的异常，如是本个任务出错，不影响别一个，都执行完成了，才会返回
                {
                    foreach (var single in ex.InnerExceptions)
                    {
                        Console.WriteLine(single.Message);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                Console.ReadLine();
            }
        }

        #region Task测试(同步的并行执行)
        public async static  Task Step1()
        {
            try
            {
                //await进行等待后，新线程的异常可以被主线程捕捉，这是正常的,下面的代码不会被执行
                await Task.Run(() =>
                {

                    Console.WriteLine("Step1 Current ThreadID" + Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(3000);
                });

                await Task.Run(() =>
                {
                    Console.WriteLine("Step1 Current ThreadID" + Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine("ThreadTest.Test Runing");
                });
            }
            catch (Exception ex)
            {

                Console.WriteLine("ThreadTest" + ex.Message);
            }
        }
        static void test4()
        {
           
            //第一种方式开启
            var task1 = new Task(() =>
            {
                Run41();
            });

            //第二种方式开启
            var task2 = Task.Factory.StartNew(() =>
                {
                    Run42();
                });

            Console.WriteLine("调用start之前****************************\n");

            //调用start之前的“任务状态”
            Console.WriteLine("task1的状态:{0}", task1.Status);

            Console.WriteLine("task2的状态:{0}", task2.Status);

            task1.Start();

            Console.WriteLine("\n调用start之后****************************");

            //调用start之前的“任务状态”
            Console.WriteLine("\ntask1的状态:{0}", task1.Status);

            Console.WriteLine("task2的状态:{0}", task2.Status);

            //主线程等待任务执行完
            Task.WaitAll(task1, task2);

            Console.WriteLine("\n任务执行完后的状态****************************");

            //调用start之前的“任务状态”
            Console.WriteLine("\ntask1的状态:{0}", task1.Status);

            Console.WriteLine("task2的状态:{0}", task2.Status);

            Console.Read();
        }

        static void Run41()
        {
            Thread.Sleep(1000);
            Console.WriteLine("\n我是任务1");
        }

        static void Run42()
        {
            Thread.Sleep(2000);
            Console.WriteLine("我是任务2");
        }
        #endregion

        #region  Parallel并行的测试(同步的并行执行)

        #region  Parallel.Invoke*并行执行
        /// <summary>
        /// Parallel.Invoke*并行执行
        /// </summary>
        static void test()
        {
            var watch = Stopwatch.StartNew();

            watch.Start();

            // Run1();

            // Run2();

            Console.WriteLine("我是串行开发，总共耗时:{0}\n", watch.ElapsedMilliseconds);

            watch.Restart();
            //这里是同步中执行的
            Parallel.Invoke(Run1, Run2);

            watch.Stop();

            Console.WriteLine("我是并行开发，总共耗时:{0}", watch.ElapsedMilliseconds);

            Console.Read();
        }
        #endregion

        #region Parallel.for 分区采用Partitioner.Create
        /// <summary>
        /// Parallel.for
        /// Paraller.for它会在底层根据硬件线程的运行状况来充分的使用所有的可利用的硬件线程
        /// </summary>
        static void test1()
        {

            for (int j = 1; j < 4; j++)
            {
                Console.WriteLine("\n第{0}次比较", j);
                //***ConcurrentBag 提供对象的线程安全的无序集合
                //***ConcurrentBag<T>对于同一个线程值的添加和删除是非常快的，
                //因为ConcurrentBag内部将数据按线程的标识而独立存储，所以一个线程从自己的数据中移除一个数据是非常快的，
                //当然如果这个线程中没有数据，那么只能从其他线程中移除数据，此时会发生一些性能损耗从而确保线程安全！

                ConcurrentBag<int> bag = new ConcurrentBag<int>();

                var watch = Stopwatch.StartNew();

                watch.Start();

                for (int i = 0; i < 800000; i++)
                {
                    bag.Add(i);
                }

                Console.WriteLine("串行计算：集合有:{0},总共耗时：{1}", bag.Count, watch.ElapsedMilliseconds);

                GC.Collect();

                bag = new ConcurrentBag<int>();

                watch = Stopwatch.StartNew();

                watch.Start();

                Parallel.For(0, 800000, i =>
                {
                    bag.Add(i);
                });

                Console.WriteLine("并行计算：集合有:{0},总共耗时：{1}", bag.Count, watch.ElapsedMilliseconds);

                GC.Collect();



            }

            //            第1次比较
            //串行计算：集合有:800000,总共耗时：162
            //并行计算：集合有:800000,总共耗时：130

            //第2次比较
            //串行计算：集合有:800000,总共耗时：149
            //并行计算：集合有:800000,总共耗时：253-------------不一定更快

            //第3次比较
            //串行计算：集合有:800000,总共耗时：173
            //并行计算：集合有:800000,总共耗时：216

        }

        /// <summary>
        /// forEach的独到之处就是可以将数据进行分区，每一个小区内实现串行计算，分区采用Partitioner.Create实现
        /// </summary>
        static void test2()
        {
            for (int j = 1; j < 4; j++)
            {
                Console.WriteLine("\n第{0}次比较", j);

                ConcurrentBag<int> bag = new ConcurrentBag<int>();

                var watch = Stopwatch.StartNew();

                watch.Start();

                for (int i = 0; i < 3000000; i++)
                {
                    bag.Add(i);
                }

                Console.WriteLine("串行计算：集合有:{0},总共耗时：{1}", bag.Count, watch.ElapsedMilliseconds);

                GC.Collect();

                bag = new ConcurrentBag<int>();

                watch = Stopwatch.StartNew();

                watch.Start();

                Parallel.ForEach(Partitioner.Create(0, 3000000), i =>
                {
                    for (int m = i.Item1; m < i.Item2; m++)
                    {
                        bag.Add(m);
                    }
                });

                Console.WriteLine("并行计算：集合有:{0},总共耗时：{1}", bag.Count, watch.ElapsedMilliseconds);

                GC.Collect();

            }
        }

        #endregion


        /// <summary>
        /// Parallel.For  中断退出
        /// Break: 当然这个是通知并行计算尽快的退出循环，比如并行计算正在迭代100，那么break后程序还会迭代所有小于100的。
        ///Stop：这个就不一样了，比如正在迭代100突然遇到stop，那它啥也不管了，直接退出。
        /// </summary>
        static void test3()
        {
            var watch = Stopwatch.StartNew();

            watch.Start();

            ConcurrentBag<int> bag = new ConcurrentBag<int>();

            Parallel.For(0, 20000000, (i, state) =>
            {
                if (bag.Count == 50000)
                {
                    // state.Break();//元素数可能大于50000
                    state.Stop();//元素可能大于50000
                    return;
                }
                bag.Add(i);
            });

            Console.WriteLine("当前集合有{0}个元素。", bag.Count);
        }

        #region 内部子流程
        static void Run1()
        {
            Console.WriteLine("我是任务一,我跑了3s");
            Thread.Sleep(3000);
            //throw new Exception("我是任务1抛出的异常");
        }

        static void Run2()
        {
            Console.WriteLine("我是任务二，我要跑了9s");
            Thread.Sleep(9000);
            Console.WriteLine("我是任务二，我跑了--");
        }
        #endregion

        #endregion
    }
}
